package gaml.java;

import gaml.error.GamlException;
import gaml.yaml.AliasNode;
import gaml.yaml.YamlNode;
import gaml.yaml.ahchor.YamlAnchorCodeStore;
import gaml.yaml.ahchor.YamlAnchorObjectStore;


/**
 * process yaml anchor based duplicate object
 * reference resolution before process object with serializer  
 * @author shnireck
 *
 */
public class AnchorSerializer {
	final static String nonProcessingAlias = "Alias node [%s] found for non-processing object type [%s]";
	
	/**
	 * check if we have duplicate reference, create alias if we do,
	 * or serialize object normally if we do not
	 * @param <T> serializing java object type
	 * @param anchors yaml anchors store
	 * @param serializer object type specific serializer
	 * @param node yaml node to serialize object's data into
	 * @param object java object to serialize
	 * @return yaml node, in wich we serialize java object
	 * @throws GamlException 
	 */
	public static <T> YamlNode serialize (YamlAnchorObjectStore anchors, ClassSerializer <T> serializer, YamlNode node, T object) throws GamlException {
		if (! (serializer.noAnchor ())) if (anchors.checkRepeat (object, node)) {
			AliasNode alias = new AliasNode (node.getParent (), anchors.getAnchor (object));
			return alias;
		}
		
		return serializer.serialize (node, object, anchors);
	}
	
	/**
	 * check if we have alias node, get pre-deserialized object for it
	 * or desrialize node in normal way, if node is not alias
	 * @param <T> type of java object to get
	 * @param anchors yaml anchors store
	 * @param serializer base class serializer to use for yaml node deserialization
	 * @param node node to deserialize to java object
	 * @param object java object to restore data into
	 * @param store java object serializers store 
	 * @return deserialized java object
	 * @throws GamlException if pre-deserialization failed, or if alias node 
	 * found for type, which can not be processed throw duplicate reference resolution
	 */
	public static <T> T restore (YamlAnchorCodeStore anchors, ClassSerializer <T> serializer, YamlNode node, T object, ClassSerializerStore store) throws GamlException {
		if (node instanceof AliasNode) {
			if (serializer.noAnchor ()) throw new GamlException (String.format (nonProcessingAlias, node.getAnchor ().getCode (), object.getClass ().getName ()));
			else return (T) anchors.getObject ((AliasNode) node, serializer.getObjectClass (), store);
		}

		T restored = serializer.restore (node, object, anchors);
		if (null == node.getAnchor ()) 
			return restored;
		return (T) anchors.getAnchor (node.getAnchor ().getCode ()).setObject (restored).getObject ();
	} 
}
